#ifndef TCPSERVER_H
#define TCPSERVER_H

#include "Common.h"
#include "Callbacks.h"
#include "Acceptor.h"
#include "TcpConnection.h"
#include "ThreadPool.h"
// #include "EventLoop.h"
#include <functional>
#include <memory>

class EventLoop;
class Acceptor;
// class ThreadPool;
class Buffer;

class TcpServer {
public:

	TcpServer(EventLoop *loop, Acceptor *acceptor, int threadNum):loop_(loop),acceptor_(acceptor),threadNum_(threadNum){
        threadPool_ = new ThreadPool(loop_, threadNum_);
		data_ = NULL;
	}

    ~TcpServer() {

    }

    void setConnCompleteCallBack(const ConnCompleteCallBack &cb) {
    	connCompleteCallBack_ = cb;
    }

    void setConnCloseCallBack(const ConnCloseCallBack &cb) {
    	connCloseCallBack_ = cb;
    }

    void setMessageCallBack(const MessageCallBack &cb) {
    	messageCallBack_ = cb;
    }

    void setWriteCompleteCallBack(const WriteCompleteCallBack &cb) {
    	writeCompleteCallBack_ = cb;
    }

    void handleNewConnection() {

        // printf("handle a new conn start\n");
        int listenfd = acceptor_->listen_fd;
        struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
        int connected_fd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len);
        // make_nonblocking(connected_fd);
        fcntl(connected_fd, F_SETFL, O_NONBLOCK);
        

        printf("start new connection established, socket == %d\n", connected_fd);

        EventLoop *next_loop = threadPool_->getNextLoop();

        TcpConnectionPtr conn(new TcpConnection(connected_fd, next_loop));

        conn->setConnCompleteCallBack(connCompleteCallBack_);
        conn->setConCloseCallBack(connCloseCallBack_);
        conn->setMessageCallBack(messageCallBack_);
        conn->setWriteCompleteCallBack(writeCompleteCallBack_);

        // printf("handle a new conn middle\n");
        conn->connectEstablished();
        // conn->handleChannel();
        
        // next_loop->addChannelEvent(connected_fd, conn->channel);

        // printf("handle a new conn end\n");
    }
    
    void start() {

        threadPool_->start();
    	Channel *channel = new Channel(acceptor_->listen_fd, EVENT_READ, loop_);
        channel->setEventReadCallBack(std::bind(&TcpServer::handleNewConnection, this));
        loop_->addChannelEvent(channel->fd, channel);    
    }

    void setData(void *data) {
    	data_ = data;
    }

private:
	int port;
	int threadNum_;
	EventLoop *loop_;
	Acceptor *acceptor_;
	ThreadPool *threadPool_;
	void *data_;

	ConnCompleteCallBack connCompleteCallBack_;
	MessageCallBack messageCallBack_;	
	WriteCompleteCallBack writeCompleteCallBack_;
	ConnCloseCallBack connCloseCallBack_;

};


#endif